●ＳＧＬ ＦＡＱ

１．ＳＧＬテクニック集
　１−１　　スクロールがうまく表示できない場合のチェック方法
　１−２　　テクスチャテーブルの変更方法
　１−３　　描画処理単位指定の変更方法
　１−４  　ポーズ（一時停止）のかけ方
　１−５　　常駐、非常駐プログラムの作成方法について

２．ＳＧＬ関数の使用上の注意
　２−１　　スプライト表示関数用のアトリビュートテーブルについて
　２−２　　slLookAt関数の使用上の注意
　２−３　　slDispSprite関数の使用上の注意
　２−４　　slPutSprite関数の使用上の注意
　２−５　　slSlaveFunc関数の使用上の注意
　２−６　　sl16MapRA関数の使用方法について
　２−７　　ＳＧＬのＣＤライブラリについて
  ２−８　　slScrAutoDisp関数の使用上の注意
　２−９　　slLight関数の使用上の注意
　２−１０　slPutPolygon関数とslPutPolygonS関数について
　２−１１　slCurWindow関数について

３．ＳＧＬの内部処理について
　３−１　　ＳＧＬで使用している割り込みについて
　３−２  　ＳＧＬで使用しているハードウェアデバイスについて
　３−３　　ＳＧＬ上での三次元変換について
　３−４　　ＳＧＬのポリゴン表示ルーチンの処理方法について
　３−５　　光源のためのデータテーブルについて
　３−６　　ＳＧＬのZソート処理およびZデータバッファについて
　３−７　　マスタCPUとスレーブCPU間のデータの受け渡しについて
　３−８　　サウンドコントロールについて

４．ＳＧＬのトラブルシューティング
　４−１  スプライト／ポリゴンの残像現象の対応について



１．ＳＧＬテクニック集
１−１　スクロールがうまく表示できない場合のチェック方法
　SGLはシステム変数内にVDP2のレジスタ内容を待避させた領域を 60FFCC0番地から用意
しています。その内容のほとんどを Vブランクの処理でVDP2レジスタに複写しています。
  VDP2のレジスタは書き込み専用でユーザが設定した値が参照できないため、表示でき
ない原因がつきとめにくいのですが、この領域をを参照することでVDP2のレジスタに対
してどのような設定がされているのかわかります。
　デバッグ時にはこの領域を参照しておかしい現象の原因を突き止めることに利用して
ください。

１−２　テクスチャテーブルの変更方法
　slinitSystem関数で登録したテクスチャテーブルをプログラム中で変更したい場合は
以下のように行います。

　　extern TEXTURE *FormTbl;  /* システム変数内(System Work) */
　　extern TEXTURE *textbl2;  /* 変更するテクスチャテーブル  */
            :
    FormTbl = textbl2;        /* 配列の登録 */
    

１−３　描画処理単位指定の変更方法
　slinitSystem関数で登録したする描画処理単位ですが、プログラム中で変更
したい場合は以下のように行います。
　
　　extern Sint8 SynchConst;  /* システム変数内(System Work) */

    SynchConst = 変更する値;

【注意】
　Ver1.3よりVDP1の描画終了待ちフレームチェンジ（init.docを参照のこと）をサポー
トにより、一定周期のフレームチェンジからの変更（その逆の場合も）の際には、変数
の変更前に以下の関数の実行が必要です。
　　
　＜一定周期のフレームチェンジからVDP1の描画終了待ちフレームチェンジの変更＞
　　　extern Sint8 SynchConst;  /* システム変数内(System Work) */

  　　slInitSystem( .. , .. , 2 );
             :
　　　slDynamicFrame(ON);
    　SynchConst = 2;

　＜VDP1の描画終了待ちフレームチェンジから一定周期のフレームチェンジの変更＞
　　　extern Sint8 SynchConst;  /* システム変数内(System Work) */

  　　slInitSystem( .. , .. , -2 );
             :
　　　slDynamicFrame(OFF);
    　SynchConst = 2;

１−４  ポーズ（一時停止）のかけ方
　PauseFlag 変数をセットすることにより、スクロール、スプライトのデータ転送を一
時停止できるようになりました。
  以下に各ビットの意味を示します。
    _SysPause : SGLには影響の無いビットです。ユーザがポーズ中であることを知るた
                めに使用します。
    _ScrPause : スクロールのデータ転送を行いません。
    _SprPause : スプライト(ポリゴン)データの転送を行いません。

　この変数を利用してアプリケーションでポーズ（一時停止）状態を管理することがで
きます。
　  extern Sint8 PauseFlag;
  
    if(PadPush & PER_DGT_TS) {
        PauseFlag ^= _SysPause | _SprPause;
    }
    if(PauseFlag == 0) {    /* イベント使用時 */
        slExecuteEvent();
    }

１−５　常駐、非常駐プログラムの作成方法について
　プログラムやデータが大きくなり、サターンのメモリ上にすべておけない場合、デー
タ自体は使用するデータのみをあらかじめ読み込んでおいておくという方法をとること
ができますが、プログラムの場合はオーバーレイなどの手法をとる必要があります。
　しかし、そのような機能を常駐されていないので、プログラムでの工夫とリンケージ
エディタの機能を使用して行う必要があります。
　以下に一例として示しますので参考にしてください。

（１）常駐部プログラムの作成
　常駐プログラムは、最低限ファイルの読み込みや共通に使用するライブラリを置いて
おく部分として使用します。
　手順としては、CD-ROMから非常駐プログラムを指定のアドレスに読み込み、以下の2通
りの方法のどちらかでその非常駐プログラムを実行します。

　(a) 指定アドレスから呼び出す方法
　　非常駐プログラムを実行するアドレスをあらかじめ記述しておき、非常駐プログラ
　ムを読み込んだ後、このアドレスから実行します。

　　＜プログラムの記述例＞
    　　fid = GFS_NameToId((Sint8 *)fname); /* fnameは非常駐プログラム */
  　  　GFS_Load(fid, 0, 0x6080000, GFS_BUFSIZ_INF);

　　　/* 開始アドレスは非常駐プログラムのマップファイルから取得する */
　　　　((volatile void (*)())(0x6081000))();　
  　＜プログラムのリンク時の宣言＞
    　　GCC -m2 -Xlinker -Tkernal.cof -Xlinker -e -Xlinker ___Start ....

　　この例の場合、非常駐プログラムの実行開始関数のアドレスが変わった場合、この
　プログラムの再コンパイルが必要になります。

　(b) 外部宣言で関数を定義しておき、リンク時に-defsymオプションで外部宣言した関
　　数に対してアドレスを設定します。関数の実行は、非常駐プログラムを読み込んだ
　　後、実行します。

  　＜プログラムの記述例＞
        extern void SUB_main1( void );
        #define SUB_ADDR    0x06080000
　　　　
        void main( void ) 
        {
         　　   :
        /* 非常駐プログラムのロード例 */
            buf[0].type = CDBUF_COPY;
            buf[0].trans.copy.addr = (Uint32)SUB_ADDR;
                  :
            slCdLoadFile();
        /* 非常駐プログラムの実行 */
            SUB_main1();
       　　     :
      　　}
  　＜プログラムのリンク時の宣言＞
          GCC -m2 -Xlinker -defsym -Xlinker _SUB_main1=0x06081000 \
             -Xlinker -Tkernal.cof -Xlinker -e -Xlinker ___Start ....

　　非常駐部の実行開始関数のアドレスが不定になりますので、一度仮にアドレスを設
　定して、非常駐プログラムを作成後、その非常駐部分のマップファイルから本当の実
　行開始アドレスを取得して再度アドレスを設定し直してリンクする必要が場合があり
　ます。

（２）非常駐部プログラムの作成方法
　非常駐プログラムは、常に使用するプログラムやデータではなく、例えばステージ単
位でしか使用しないプログラムを実行するようにします。非常駐プログラムは複数存在
しても構いませんが、以下な点に注意して作成してください。

　(a) プログラミング時の注意
　　オブジェクトファイル内に常駐部と同じ関数名で作成しないように注意してプログ
　ラミングします。（例えば、main関数などがぶつかる可能性があります。）

　(b) 非常駐部の読み込み時の注意
　　非常駐部のスタートアドレスを常駐部の読み込み開始アドレスと同じアドレスに設
　定してください。
  
　(c) 常駐部プログラムのマップ情報の受け渡し
　　非常駐部を作成するときにリンカの-Rオプションを指定して常駐部の実行ファイル
　（例としてKernal.COF）を指定します。
　　　　　GCC -m2 -Xlinker -R -Xlinker kernal.cof　.....
　　この指定により、常駐部のシンボルを抽出して非常駐プログラムに組み込みます。
　使用するライブラリを常駐部と同様にリンクしても同じ関数が存在した場合は、-Rで
　指定したCOFFファイルの情報を優先します。

（３）常駐部から呼び出す非常駐部の実行開始アドレスの再登録
　非常駐プログラムを作成後、マップファイルから常駐部から呼び出される関数のアド
レスを調べて、リンク時に -defsymオプションで再度実行開始関数のアドレスを再設定
します。
　すでに常駐プログラム作成時のアドレスと同じ場合は行う必要はありません。


２．ＳＧＬ関数の使用上の注意
２−１　スプライト表示関数用のアトリビュートテーブルについて
  slPutSprite関数、slDispSprite関数で使用するアトリビュートテーブルは、ポリゴン
用のものとほぼ同じですが、先頭の２つのデータがなくなっています。
  C言語でこのテーブルを作成する場合、SPR_ATTR型が宣言されており、SPR_ATTRIBUTE
マクロを使用することができます。
 (例) SPR_ATTR attr_AM2Logo = {
	      SPR_ATTRIBUTE(PN_AM2_Logo,CL_AM2_Logo,No_Gouraud,
	      Window_In|ECdis,sprNoflip|_ZmCB)
	  };

  _ZmCB はポジションがスプライトのどの位置を指すかを指定するもので、
以下の9つが定義されています。
        _ZmLT    _ZmCT    _ZmRT
           +-------+-------+
           |       |       |
     _ZmLC +----_ZmCC------+ _ZmRC
           |       |       |
           +-------+-------+
        _ZmLB    _ZmCB    _ZmRB

２−２　slLookAt関数の使用上の注意
  slLookAt 関数では Ｙ軸と平行になるような視線は作成できません。
（真上や、真下を向くような場合には、ＸあるいはＺ軸方向にすこしずらして下さい）
　カメラ設定をする場合、 slLookAt関数を使用する場合と、slTranslate関数と
slRot?関数とを組み合わせて使用する場合とを使い分けて下さい。
  例えば、プレイヤーの飛行機から見た画面を作成したい場合には、以下のようにしま
す。
	slRotX(-plptr->ang[X]) ;
	slRotY(-plptr->ang[Y]) ;
	slRotZ(-plptr->ang[Z]) ;
	slTranslate(-plptr->pos[X] , -plptr->pos[Y] , -plptr->pos[Z]) ;

  また、固定カメラが特定の車を追いかける場合には、以下のようにします。
	slLookAt(cmptr->pos , tgptr->pos , toFIXED(0.0)) ;

２−３　slDispSprite関数の使用上の注意
　slDispSprite関数 でスケールに 1.00を指定した場合、元絵よりも1ドットずつ大きく
表示されます。
  これはハードウエアが指定した表示サイズよりも1ドット大きく表示してしまうためで
、これを避けたい場合には スケールに 0.99999 を指定して下さい。この値は、
SL_DEF.H で ORIGINAL というマクロにより定義されています。

２−４　slPutSprite関数の使用上の注意
  slPutSprite関数でポジションに大きな値を指定するとオーバーフローして、画面外の
スプライトが表示されてしまう場合があります。
　slTranslate関数と組み合わせ、slPutSprite 関数に渡すポジションが大きくならない
ように注意して下さい。

２−５　slSlaveFunc関数の使用上の注意
　slSlaveFunc関数で実行させる関数ではマスターCPUの変数を書き換えることのないよ
うに注意して下さい。もしも書き換える場合には必ずマスターCPU側で、キャッシュを
パージ（初期化）して下さい。また、スレーブCPUに対してファンクションを発行する
ような関数（スプライトコントロール関係等）は実行しないで下さい。

２−６　sl16MapRA関数の使用方法について
　scroll.docに明記しておりますが、sl16MapRA関数に渡すページナンバーのテーブルが
実際のVRAMと合致していないために正しく動作していない場合が多いようです。
  sl16MapRA関数, sl16MapRB関数ではテーブルに入っているページナンバーがVRAMの先
頭から数えた通し番号になっているものとして、テーブルの0番目の要素を0x800倍し、
その値をアドレスとして登録します。
　例えば、
    #define    RBG0_CEL_ADR    (VDP2_VRAM_A0)
    #define    RBG0_MAP_ADR    (VDP2_VRAM_B0)
    #define    RBG0_COL_ADR    (VDP2_COLRAM)
    #define    RBG0_KTB_ADR    (VDP2_VRAM_A1)
    #define    RBG0_PRA_ADR    (VDP2_VRAM_A1+ 0x1fe00)
という例のように、VRAM-B0バンクにパターンネームがある場合、テーブルには128,132,
136...といった値が設定されなければなりません。(0,4,8...というデータをセットする
ケースが多いようです)
    #define　　MAPOFFSET  (RBG0_MAP_ADR-VDP_VRAM_A0)/0x800
    #define    DD    4+MAPOFFSET
    Uint8    map[16] = {
         0*DD, 1*DD, 2*DD, 3*DD,
         4*DD, 5*DD, 6*DD, 7*DD,
         8*DD, 9*DD,10*DD,11*DD,
        12*DD,13*DD,14*DD,15*DD,
    };
    #undef    DD
    sl16MapRA(map);

　上記のような方法で設定すれば、正しく設定することができます。

２−７　ＳＧＬのＣＤライブラリについて
　SGLでは、CD-ROMをアクセスするライブラリとして、slCdxxxx関数を用意していますが、
あまり高度な使い方はできません。CinepakライブラリやMPEGライブラリ、TrueMotionを
使用する場合は、ファイルシステムライブラリ(GFS_xxxx関数)やストリームライブラリ
(STM_xxxx関数)を使用するようにしてください。このライブラリは、SGLで提供している
LIBCD.Aに組み込まれています。

２−８　slScrAutoDisp関数の使用上の注意
　slScrAutoDisp関数は、表示するスクロール面の登録やサイクルパターンテーブルを自
動的に作成する便利な関数ですが、すべてのケースに対応できる関数ではありません。
この関数で出力されるサイクルパターンテーブルのデータは、デバッグ時に必ずチェッ
クして、内容に応じて修正するようにしてください。
　slScrAutoDisp関数で設定されたサイクルパターンテーブルはSGLのシステム変数領域
(060FFC00番地)の0x0D0〜0x0x0DFまでの領域に格納されています。

２−９　slLight関数の使用上の注意
　SGLのチュートリアルマニュアルに、slLight関数を指定時にカレントマトリクスにス
ケール操作がかかっている場合、光源計算が正常に行われない場合があると記述してい
ます。（SGL REFERENCEマニュアル slLightの項にも記載）
　SGL内部の光源計算は、光源ベクトルと各ポリゴンの法線ベクトルとの内積値を元に輝
度計算を行なっています。スケール値を大きくする事で、各ポリゴンの法線ベクトルも拡
大してしまいます。その為、各ポリゴンの輝度差がなくなり、陰の領域に来た時急にポリ
ゴンが暗くなってしまう場合があります。
　その対応として、スケーリング操作をした際、光源の方向ベクトルに対してもスケーリ
ング操作をすることにより対応することが可能です。
　例えば、スケール値１の時と同様の結果を得るには、
　　　元の法線ベクトル n:( nx, ny, nz )
　　　スケーリング値   m:( mx, my, mz )
　　　光源ベクトル     l:( lx, ly, lz )
とした時、スケールを掛けない時の法線ベクトルと光源の方向ベクトルとの内積は、
  　　I1 = nx * lx + ny * ly + nz * lz
となり、スケールを掛けた時、
  　　n:( mx * nx, my * ny, mz * nz )
となります。
　光源ベクトルに何も施さない時、
　　  I2  = mx * nx * lx + my * ny * ly + mz * nz * lz
　　     != I1
となり、l1とは内積値が違ってしまいます。
　その対応をするために、ベクトルの各成分をスケーリング値で割ります。
　　　l:( lx / mx, ly / my, lz / mz  )
　すると内積は、
　　　I3 = mx * nx * lx / mx + my * ny * ly / my + mz * nz * lz / mz
　　　　 = nx * lx + ny * ly + nz * lz
　　　　 = I1
となり、l1と同じ内積値になります。
　これをプログラム上に適用すると、下記のようなプログラムになります。
＜例＞
    extern FIXED MsLightVector[ XYZ ]; /* SGLの光源情報(システム変数) */
    typedef struct {
        FIXED pos[XYZ];
        ANGLE ang[XYZ];
        FIXED sca[XYZ];
        MATRIX base;
    } CAMERA;
    static CAMERA cam;

    void main( void )
    {
        FIXED UnitLight[ XYZ ];
        FIXED CurrentLight[ XYZ ];

        slInitSystem(TV_320x224, NULL, 1);
        slPrint("Sample slLight Function", slLocate(6,2));
     /* カメラ位置の初期化 */
        cam.pos[X] = cam.pos[Y] = toFIXED(0);
        cam.pos[Z] = toFIXED(220.0);
        cam.ang[X] = cam.ang[Y] = cam.ang[Z] = DEGtoANG(0);
        cam.sca[X] = cam.sca[Y] = cam.sca[Z] = toFIXED(1);
        slUnitMatrix( cam.base );
     /* 光源の設定(誤差がでるので直接光源データを書き換えないようにする) */
        UnitLight[ X ] = MsLightVector[ X ];
        UnitLight[ Y ] = MsLightVector[ Y ];
        UnitLight[ Z ] = toFIXED( 1.0 );
        while(-1) {
        /* パッド情報の取得する関数 */
            get_pad();
        /* パット情報の変化があった場合、真になる */
            if ( check_pad_change( &cam ) ){
                slPushMatrix();
                {
                    slLoadMatrix(cam.base);
                    slTransposeMatrix();
                    slRotX(cam.ang[X]);
                    slRotY(cam.ang[Y]);
                    slRotZ(cam.ang[Z]);
                    slTransposeMatrix();
                    slGetMatrix(cam.base);
                }
                slPopMatrix();
            }

            slPushMatrix();
            {
                slTranslate(cam.pos[X], cam.pos[Y], cam.pos[Z]);
                slMultiMatrix(cam.base);
            /* スケール処理 */
                slScale(cam.sca[X], cam.sca[Y], cam.sca[Z]);
            /* スケール処理を光源ベクトルに反映 */
                CurrentLight[ X ] = slDivFX( cam.sca[ X ], UnitLight[ X ] );
                CurrentLight[ Y ] = slDivFX( cam.sca[ Y ], UnitLight[ Y ] );
                CurrentLight[ Z ] = slDivFX( cam.sca[ Z ], UnitLight[ Z ] );
                slLight( CurrentLight );
                slPutPolygon(pdata);
            }
            slPopMatrix();
            slSynch();
        }
    }

※MsLightVectorはシステム変数で、現在の光線ベクトルを示しています。
（SGL REFERENCE ManualのMsLightは変更されており、MsLightVectorが正しいシステム
　変数名です。）

２−１０　slPutPolygon関数とslPutPolygonS関数について
　slPutPolygon関数とslPutPolygonS関数は以下のように動作が違いますので注意してく
ださい。
（１）slPutPolygon関数の動作
　slPutPolygon関数は、マスタCPUでスレーブCPUの未実行ファンクションの状態を調べ
て次の３種類の処理に分けて動作します。
  (a) 未実行ファンクションが無い場合
　  スレーブCPUに表示用の演算をすべて任せるため、以下のデータをバッファに積んで
  スレーブCPUにリクエストを発行します。
　  ・頂点の登録数
　  ・頂点データテーブルのアドレス
　  ・ポリゴンの登録数
　  ・ポリゴンデータテーブルのアドレス
　  ・アトリビュートデータテーブルのアドレス
　  ・演算用マトリクス
  (b) 未実行ファンクションがひとつの場合
　  スレーブCPUのファンクション読み出しポインタと、マスタCPUの書き込みポインタ
  との差を調べて、この差がデータひとつ分であれば、頂点データの回転と平行移動と
  透視変換をマスタCPUが行います。この演算の後、以下のデータをバッファに積んで、
  スレーブCPUにリクエストを発行します。
　  ・頂点の登録数
　  ・演算後の頂点データテーブルのアドレス
　  ・ポリゴンの登録数
　  ・ポリゴンデータテーブルのアドレス
　  ・アトリビュートデータテーブルのアドレス
　  ・演算用マトリクスの回転部分(３ｘ３)
  (c) 未実行ファンクションがふたつ以上の場合
  　ポリゴンデータ作成に関する部分をすべてマスタCPUが行います。
  データ作成の後、作成データをＺバッファに登録するため、スレーブCPUにリクエスト
  を発行します。
　  ・ポリゴン(スプライト)データテーブルのアドレス
　  ・ポリゴンの登録数
　  ・頂点の登録数

　ポリゴンの演算に使用されるバッファは、マスタCPUとスレーブCPUとの書き込みがぶ
つからないように共有しています。
　共有しているのは頂点データの演算結果を格納するバッファと、最終的に作成される
ポリゴンデータのバッファでこれらは以下のようにして競合を防いでいます。
　●頂点データの演算用バッファ
　　使用するバッファサイズは頂点の数により決まるのでマスタCPUとスレーブCPUの双
　方が相手の使用分も含めて自分のポインタを進めて書き込みが重ならないようにして
　います。
　●ポリゴンデータのバッファ
　　ポリゴンデータは表示対象となったポリゴンの数によって使用量が変化するため、
　テーブル上のポリゴン登録数ではポインタを進められないので、スレーブCPUはバッフ
　ァを先頭から、マスタCPUがバッファを後ろから使用していくことで書き込みが重なら
　ないようにしています。

（２）slPutPolygonS関数の動作
　　slPutPolygonS関数では、スレーブCPU側の処理状況をチェックせずにすべての表示
　用の処理を行なわせます。スレーブCPU側に強制的に行わせることにより、メインCPU
　側でアプリケーション固有の処理を行わせて、プログラム全体の処理を両CPUバランス
　よく動作させることができます。


２−１１　slCurWindow関数について
  slWindow関数は、関数を実行した時点で手前のウィンドウに切り替わりましたが、
slCurWindow関数を実行することで表示するウィンドウを指定することができます。
これは、ウィンドウ情報を常に保持するなっているので、ウィンドウの設定回数を減ら
すことにもなります。
　＜使用例＞
　　　slCurWindow(winFar);
      slWindow(--- for Far side Window ---);
　　　slCurWindow(winNear);
      slWindow(--- for Near side Window ---);
　　　...
　　　slCurWindow(winFar);
      slPutPolygon(PD_XX);        /* ゲーム画面への表示 */
　　　slCurWindow(winNear);
      slPutPolygon(PD_xx);        /* マップへの表示 */

　　　slCurWindow(...);

　表示ウィンドウは、slSynch関数実行後 winFar に表示され、ウィンドウが切り替わる
slWindow関数の実行（slPutPolygon関数などの表示関数実行後）、もしくはslCurWindow
関数を実行するまで、同じウィンドウに対して表示処理が行われます。
　この関数を使用する上での注意点としてslCurWindow関数によって切り替わるパラメー
タは以下の関数によって設定されたもののみです。slWindow関数、slZdspLevel関数、
slPerspective関数、環境マトリクス、光源ベクトルについては再設定されませんので、
注意してください。
　slSprWinNum関数を実行するとカレントウィンドウナンバー（winFar、winNear）を返
します。


３．ＳＧＬの内部処理について

３−１　ＳＧＬで使用している割り込みについて
　SGL では以下の割り込みを使用しています。
（１）VブランクIN割り込み
　SGL ではVブランクINの割り込みで以下の処理を行っています。
　・FRTのカウンタを読み込んで、FRT_Count変数に設定します。
　・VDP2のレジスタにスクロール情報のデータを転送します。
　　データはSGLのシステム変数領域に登録されている情報をCPU DMAのチャンネル1番
　　を使用して転送します。
　　この転送は、SynchCount変数が0の時でかつPauseFlag変数に_ScrPauseが定義され
　ていない場合に行われます。
　・データ転送処理(slTransferEntry関数)を行います。
　・ユーザ登録関数(slIntFunction関数で登録されたユーザ関数)を実行します。
　・ペリフェラルの処理を実行します。始めに読み込んだFRT_Countから68カウンタ進ん
　だ後に実行されます。(300usec)

（２）VブランクOUT割り込み
　SGL ではVブランクOUTの割り込み処理で以下の事を行っています。
　・VDP1のフレームコントロール処理を行います。SynchCount変数が1の場合にイレース
　ライトモードのセット、0の場合にフレームチェンジがセットされます。
　・スプライトデータの転送を行います。
　・ペリフェラルデータの読み込みを行います。
　・SynchCountの減算を行います。

３−２  ＳＧＬで使用しているハードウェアデバイスについて
　SGLでは、以下のハードウェアデバイスを使用しており、そのデバイスを使用するにあ
たり制限される場合があります。

（１）DMAコントローラについて
　SEGASATURNでは、DMAコントローラとしてSCUに内蔵されたDMAとCPUに内蔵されたDMAの
2種類あり、SGLでは両方のDMAを使用しています。

　(a)SCUに内蔵のDMAコントローラについて
　　SCUのDMAには、0〜2の3つのチャンネルが用意されています。SGLでは、以下のよう
　に使用しています。
    【チャンネル 0】
      ・未使用
　　【チャンネル 1】
　　　・スプライト(ポリゴン)データの転送
      ・毎フレーム(slInitSystem関数の設定で変わる場合があります)で使用
　　【チャンネル 2】
　　　・PCMストリームデータの転送、ブランキング内データ転送で使用

　　その他にSBLで用意されていたDMA_関数群も組み込まれています。
　　いずれもSCU-DMAが動作中であれば、SGL内部変数を見てウエイトするようにしてい
　ますが、設定中に割込みがかかった場合にはチェックできませんので、必ずSGLで用意
　したDMAライブラリを使用してください。
    SCUのDMAに関するハードウェア内容については、
    ・HARDWARE MANUAL Vol.1「SCUユーザーズマニュアル」
    ・TECHNICAL INFORMATION 
    　「Developer's Information STN-10 SCU仕様変更による制限事項・注意事項」を
    参照するようにお願いします。

  (b) CPUに内蔵のDMAコントローラについて
  　CPU DMA には、0 と 1の2つのチャンネルがあります。SGLでは、以下のように使用
  しています。
  　【チャンネル 0】
  　　サウンド関係のデータ転送用、slDMACopy関数、slDMAXCopy関数
  　【チャンネル 1】
  　　Vブランク割込み内でスクロールのデータ転送

　　チャンネル 1については、今後SGLのシステム予約としますのでアプリ側では使用し
　ないでください。
　　いずれもCPU-DMAが動作中であれば、SGL内部変数を見てウエイトするようにしてい
　ますが、設定中に割込みがかかった場合にはチェックできませんので、必ずSGLで用意
　したDMAライブラリを使用してください。
    CPUのDMAに関するハードウェア内容については、
    「SH7095ハードウェアマニュアル 9.ダイレクトメモリアクセスコントローラ」
　を参照するようにお願いします。

（２）FRT(フリーランニングタイマ)について
　　CPU に内蔵された FRT をペリフェラルリクエスト発行のタイミングチェック用に
　Vブランク割込み処理内でカウンタの読み出しするために使用しています。クロックを
　128分周した設定でタイマが動作しているものとして使用していますので、アプリケー
　ションでは分周比を変更しない範囲で使用してください。

（３）CPU内蔵のキャッシュについて
　　SGLでは4Wayモードで使用しています。また、キャッシュをパージする方法は、コン
　トロールレジスタのパージビットを使用する方法でクリアしています。

（４）CPU内蔵の乗算器、除算器について
　　SGLでは割込み処理以外で使用しています。アプリケーションでは問題なく使用する
　ことが可能です。

３−３　ＳＧＬ上での三次元変換について
　SGLでは、カメラはZ軸の原点上にあり、常にZ軸のプラス方向を向いています。
したがって物体を表示する場合、物体をカメラの視界内に平行移動、回転操作をするこ
とによって、表示させるようにします。
　物体はカメラから物体までを結んだ線で、投影面に交わる位置で投影されます。
これはカメラ、物体間の距離と、カメラ、投影面間の距離との相似な三角形を計算する
ことで求められます。
　通常物体は投影面よりも遠い位置にあるため、縮小されて表示されますが、投影面よ
りも近い物体は逆に拡大されます。カメラに非常に近くなった場合、投影面への投影が
正しくできなくなるため、SGLでは物体として表示されるのはカメラと投影面間の1/2の
位置まで（slZdspLevel関数により1/4 あるいは 1/8に変更可）で、これよりも近い場合
は表示されません。

３−４　ＳＧＬのポリゴン表示ルーチンの処理方法について
　SGLのポリゴン表示は、マスタCPUからスレーブCPUに対して、演算に必要なデータを渡
し、リクエストを発行します。ただし、スレーブCPUの処理状況により演算の一部をマス
タCPUが代行します。
　スレーブCPUは渡されたデータを以下の順に処理します。

（１）頂点の回転、平行移動および透視変換の実行
　　回転と平行移動は、通常のマトリクス演算を行います。ただし、後に透視変換があ
　るため、Z → Y → X の順に演算します。
　　　　Z' = M02 * X + M12 * Y + M22 * Z + M32
　　このZ' が視点より後ろにあったり、視点に非常に近い場合、スクリーンの投影でオ
　ーバーフローを起こしやすくなるため、この時は Z' = DS / 4 として演算します。
　（slZdspLevel関数により変更可能）
    このZ' を使用して、透視変換係数を算出します。
    透視変換係数k は、以下のようになります。
    　　DX = X' * DS / Z'
    　　DY = Y' * DS / Z'
　　上記式のDS / Z'にあたる部分が透視変換係数kになり、この計算には除算が必要に
　なるため、Z'を先に計算しています（除算には39クロック必要になります）。
　　　　Y' = M01 * X + M11 * Y + M21 * Z + M31
　　　　X' = M00 * X + M10 * Y + M20 * Z + M30
　　除算の結果がでるまでにY'、X'を計算しておきます。
　　透視変換係数k が計算されたら、X'と Y'にかけて、表示位置Dx、Dyとします。
　　　　Dx = X' * k
　　　　Dy = Y' * k
　　これらの演算結果をバッファにセットします。
　　バッファには、
　　　　FIXED  X'
　　　　FIXED  Y'
　　　　FIXED  Z'
　　　　Sint16 Dx
　　　　Sint16 Dy
　を組にして、頂点の数だけ順に登録していきます。

（２）各ポリゴンに対する表示判定処理と表示データの作成
　(a) ポリゴンの法線ベクトルと回転行列にかけて、現在の向きの合わせます。
　　マトリクス演算の平行移動分を除いた演算を行います。
　　　　nX = M00 * NX + M10 * NY + M20 * NZ
　　　　nY = M01 * NX + M11 * NY + M21 * NZ
　　　　nZ = M02 * NX + M12 * NY + M22 * NZ
　　この演算によって得られたベクトル（nX、nY、nZ）とポリゴンに使用されている頂
　点の一つ（PX、PY、PZ）との内積をとり、その結果の符号を調べて表裏判定します。
　　頂点データはバッファ中の頂点に該当する X'、Y'、Z'を使用します。この表裏判定
　で裏と判定されたポリゴンは面属性を調べて、片面ポリゴンであればここで次のポリ
　ゴン処理に移りますが、両面であれば法線ベクトルの向きを逆に（各要素の符号を反
　転します）します。

　(b) ソーティングモードにより、ポリゴンのZ位置を求めて表示範囲内であるか調べま
　　す。ポリゴンに使用されている4頂点のZ位置（バッファ中のZ'の上位16ビット）か
　　らポリゴンのZ位置を決め、Zlimitまでに入っているかどうか調べます。表示対象で
　　あればZバッファに登録して、対象外であれば次のポリゴンに移ります。

　(c) UseClipの使用時、画面上の表示位置がハードウェア上で有効範囲内であるか調べ
　　ます。ハードウェアで使用できる位置データの有効範囲は、X が-2048〜+2047、
　　Y が -1024〜+1023であるので、この範囲内であるかどうか調べます。
　　　これには消失点の位置をオフセットとして加え、最大値と比較して越えていなけ
　　れば有効範囲内になります。
　　　　CX = DX + ClipXAdder
　　　　CY = DY + ClipYAdder
　　　この演算を行い、いずれかがマイナスかあるいは最大値を越えていれば有効範囲
　　外となります。
　(d) UseLight使用時の光源による輝度の計算を行います。法線ベクトルと光源ベクト
    ルとの内積を取り、この値によってカラーデータにオフセットをかけます。
　　　オフセットデータは、CLOfstBuf(MEMORY.DOC)というバッファにシステムの初期
　　化の際に用意してあり、以下のような形式になっています。
　　　RGBの値はそれぞれ 0 〜 31の値で、輝度を0〜31（内積の上位5ビットでマイナス
　　の場合には0扱いに、1.0以上になった場合は31扱い）としています。
　　　それぞれのグループにはカラーデータ0〜31に対する発色データが入っており、そ
　　れらは輝度が0の場合に元のカラーの0.5倍、輝度が31の場合には1.5倍になる値が用
　　意され、最大値が31となっています。（カラーテーブルについては３−５にて説明
　　します）
　　　テクスチャを使用している場合には上記の方法がとれないため、VDP1のグーロー
　　シェーディングを利用してテクスチャ全体にカラーオフセットをかけるようにして
　　います。
　(e) ポリゴン（スプライト）データの作成を行います。テクスチャであれば、アトリ
　　ビュートのテクスチャナンバーからテクスチャ（元絵）のサイズとCGアドレスを調
　　べて、パラメタのセットおよび表示モード、グーローシェーディングテーブルを必
　　要に応じてセットします。
　　　ポリゴンの4頂点の表示位置を（１）で作成したバッファから取り出してパラメタ
　　にセットして1ポリゴン分の終了となります。
　(f) 残りのポリゴン数を調べて、(a)から処理を繰り返します。残りポリゴン数が0に
　　なったら処理を終了します。

３−５　光源のためのデータテーブルについて
　SGLのポリゴン表示時、UseLightを宣言した場合に使用される光源テーブルの内容を記
します。SGLでは、slInitSystem関数内でCLOfstBufの領域（MEMORY.DOCを参照の事）
にこのテーブルを作成していますが、汎用的に作成しているのでアプリケーションによ
って合わない場合があります。このテーブルの内容を変更することにより、独自の光源
を表現できます。
　テクスチャを使用している場合は、VDP1のグーローシェーディングテーブルを使用し
ます。このテーブルについても変更することが可能です。（MEMORY.DOCを参照の事）
　テクスチャの光源計算の注意点としては、カラーモードがRGBモードの場合のみに行い
ます。カラーパレットモードの場合は行いません。
　以下にそれぞれのカラーテーブルの内容を記します。

●＜ポリゴンの場合　光源テーブル(CLOfstBuf)　輝度0〜31＞
　( 0) 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,A,A,B,B,C,C,D,D,E,E,F,F
　( 1) 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,9,9,A,A,B,B,C,C,D,D,E,E,F,F,10
　( 2) 0,0,1,1,2,2,3,3,4,5,5,6,6,7,7,8,9,9,A,A,B,B,C,C,D,E,E,F,F,10,10,11
　( 3) 0,0,1,1,2,2,3,4,4,5,5,6,7,7,8,8,9,A,A,B,B,C,D,D,E,E,F,10,10,11,11,12
　( 4) 0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9,A,A,B,B,C,D,D,E,F,F,10,10,11,12,12,13
　( 5) 0,0,1,1,2,3,3,4,5,5,6,7,7,8,9,9,A,B,B,C,D,D,E,F,F,10,11,11,12,13,13,14
　( 6) 0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,A,B,B,C,D,D,E,F,F,10,11,11,12,13,13,14,15
　( 7) 0,0,1,2,2,3,4,5,5,6,7,7,8,9,A,A,B,C,C,D,E,F,F,10,11,11,12,13,14,14,15,16
　( 8) 0,0,1,2,3,3,4,5,6,6,7,8,9,9,A,B,C,C,D,E,F,F,10,11,12,12,13,14,15,15,16,
　　　17
　( 9) 0,0,1,2,3,3,4,5,6,7,7,8,9,A,A,B,C,D,E,E,F,10,11,11,12,13,14,15,15,16,17,
　　　18
　(10) 0,0,1,2,3,4,4,5,6,7,8,8,9,A,B,C,D,D,E,F,10,11,11,12,13,14,15,15,16,17,
　　　18,19
　(11) 0,0,1,2,3,4,5,5,6,7,8,9,A,A,B,C,D,E,F,10,10,11,12,13,14,15,15,16,17,18,
　　　19,1A
　(12) 0,0,1,2,3,4,5,6,7,7,8,9,A,B,C,D,E,E,F,10,11,12,13,14,15,15,16,17,18,19,
　　　1A,1B
　(13) 0,0,1,2,3,4,5,6,7,8,9,9,A,B,C,D,E,F,10,11,12,13,13,14,15,16,17,18,19,1A,
　　　1B,1C
　(14) 0,0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,F,10,11,12,13,14,15,16,17,18,19,1A,1B,
　　　1C,1D
　(15) 0,0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10,11,12,13,14,15,16,17,18,19,1A,1B,
　　　1C,1D,1E
　(16) 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,
　　　1D,1E,1F
　(17) 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,
　　　1D,1E,1F
　(18) 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,
　　　1E,1F,1F
　(19) 0,1,2,3,4,5,6,7,8,9,A,C,D,E,F,10,11,12,13,14,15,16,18,19,1A,1B,1C,1D,1E,
　　　1F,1F,1F
　(20) 0,1,2,3,4,5,6,7,9,A,B,C,D,E,F,10,12,13,14,15,16,17,18,19,1B,1C,1D,1E,1F,
　　　1F,1F,1F
　(21) 0,1,2,3,4,5,6,8,9,A,B,C,D,F,10,11,12,13,14,15,17,18,19,1A,1B,1C,1E,1F,
　　　1F,1F,1F,1F
　(22) 0,1,2,3,4,5,7,8,9,A,B,D,E,F,10,11,13,14,15,16,17,18,1A,1B,1C,1D,1E,1F,
　　　1F,1F,1F,1F
　(23) 0,1,2,3,4,6,7,8,9,A,C,D,E,F,11,12,13,14,15,17,18,19,1A,1C,1D,1E,1F,1F,
　　　1F,1F,1F,1F
　(24) 0,1,2,3,5,6,7,8,A,B,C,D,F,10,11,12,14,15,16,17,19,1A,1B,1C,1E,1F,1F,1F,
　　　1F,1F,1F,1F
　(25) 0,1,2,3,5,6,7,8,A,B,C,E,F,10,11,13,14,15,17,18,19,1A,1C,1D,1E,1F,1F,1F,
　　　1F,1F,1F,1F
　(26) 0,1,2,3,5,6,7,9,A,B,D,E,F,11,12,13,15,16,17,18,1A,1B,1C,1E,1F,1F,1F,1F,
　　　1F,1F,1F,1F
　(27) 0,1,2,4,5,6,8,9,A,C,D,E,10,11,12,14,15,16,18,19,1A,1C,1D,1E,1F,1F,1F,1F,
　　　1F,1F,1F,1F
　(28) 0,1,2,4,5,6,8,9,B,C,D,F,10,11,13,14,16,17,18,1A,1B,1C,1E,1F,1F,1F,1F,1F,
　　　1F,1F,1F,1F
　(29) 0,1,2,4,5,7,8,9,B,C,E,F,10,12,13,15,16,17,19,1A,1C,1D,1E,1F,1F,1F,1F,1F,
　　　1F,1F,1F,1F
　(30) 0,1,2,4,5,7,8,A,B,C,E,F,11,12,14,15,17,18,19,1B,1C,1E,1F,1F,1F,1F,1F,1F,
　　　1F,1F,1F,1F
　(31) 0,1,2,4,5,7,8,A,B,D,E,10,11,13,14,16,17,18,1A,1B,1D,1E,1F,1F,1F,1F,1F,
　　　1F,1F,1F,1F,1F

●＜テクスチャ使用時　VDP1グーローシェーディングテーブル　輝度0〜31＞
　( 0) 0000  0000  0000  0000　　( 1) 0421  0421  0421  0421
　( 2) 0842  0842  0842  0842　　( 3) 0C63  0C63  0C63  0C63
　( 4) 1084  1084  1084  1084　　( 5) 14A5  14A5  14A5  14A5
　( 6) 18C6  18C6  18C6  18C6　　( 7) 1CE7  1CE7  1CE7  1CE7
　( 8) 2108  2108  2108  2108　　( 9) 2529  2529  2529  2529
　(10) 294A  294A  294A  294A　　(11) 2D6B  2D6B  2D6B  2D6B
　(12) 318C  318C  318C  318C　　(13) 35AD  35AD  35AD  35AD
　(14) 39CE  39CE  39CE  39CE　　(15) 3DEF  3DEF  3DEF  3DEF
　(16) 4210  4210  4210  4210　　(17) 4631  4631  4631  4631
　(18) 4A52  4A52  4A52  4A52　　(19) 4E73  4E73  4E73  4E73
　(20) 5294  5294  5294  5294　　(21) 56B5  56B5  56B5  56B5
　(22) 5AD6  5AD6  5AD6  5AD6　　(23) 5EF7  5EF7  5EF7  5EF7
　(24) 6318  6318  6318  6318　　(25) 6739  6739  6739  6739
　(26) 6B5A  6B5A  6B5A  6B5A　　(27) 6F7B  6F7B  6F7B  6F7B
　(28) 739C  739C  739C  739C　　(29) 77BD  77BD  77BD  77BD
　(30) 7BDE  7BDE  7BDE  7BDE　　(31) 7FFF  7FFF  7FFF  7FFF

３−６　ＳＧＬのZソート処理およびZデータバッファについて
　SGLが行なっているZソート処理とZバッファデータの構成について、説明します。説明
はZソートにする前に行なう透視変換と表裏判定について説明し、Zソート処理の方法と、
Zデータバッファ構成およびポリゴンデータの構成、ハードウェアに転送する方法まで説
明します。
（１）透視変換の演算式
　回転、平行移動については通常のマトリクス演算を展開した形で実行しています。
　　　X' = M00 * X + M10 * Y + M20 * Z + M30
　　　Y' = M01 * X + M11 * Y + M21 * Z + M31
　　　Z' = M02 * X + M12 * Y + M22 * Z + M32
　これによって得られたX'、Y'、Z'を使用して透視変換を行います。
　透視変換では、
　　  DX = X' * (DS / Z')
　　  DY = Y' * (DS / Z')     ; DSはスクリーン位置
の式を使用していますが、このまま実行すると除算が2回必要になるので先に(DS / Z')
を計算して、この値にX'、Y'をかけて表示用の位置DX、DYとします。また、Z'がマイナ
スであったり、0に近い場合には正しく投影できないため、(DS / 4)よりも小さい場合に
は(DS / 4)として計算します。
（２）ポリゴンの表裏判定の演算式
　ポリゴンの表裏判定は、面の法線ベクトルと視点ベクトルとの内積を取り、その結果
の符号をみることで判定しています。
　視点ベクトルは、正投影の場合Z軸になりますが、透視変換であるので面に向かうベク
トルとなり、これにはポリゴンの1頂点の位置ベクトルを代用することができます。
　以上から、表裏判定をするためには、
　(a) 面の法線ベクトルを上記の回転演算により表示される面に合わせます。ただし、
    平行移動はしません。
　　　  nX = M00 * NX + M10 * NY + M20 * NZ
　　　  nY = M01 * NX + M11 * NY + M21 * NZ
　　　  nZ = M02 * NX + M12 * NY + M22 * NZ
　(b) １頂点の位置ベクトルと(1)との内積をとります。
　　　  P = nX * PX + nY * PY + nZ * PZ
      このPがマイナスであれば視点に向かっているので、表示の対象になります。
（３）Zソート処理
　プライオリティを決めるためのソーティングは、Z位置に対応したバッファに表示デー
タのアドレスを登録して、Zの遠いものから順に拾い出す方式で、この方式では比較処理
がないため高速化が期待できますが、メモリ消費とデータに登録されていないバッファ
の空読みという無駄な処理があるため、これらを軽減するためにZポジション(15ビット)
を上下2バイトに分け、まず上位バイトを基準にしてソートし、エントリーされたZ位置
に対して二次のソートを行うことで、メモリの軽減と空読み回数の低下を行なっていま
す。
（４）Zバッファとポリゴンデータの構成
　SGLのポリゴンデータは、ハードウェアで使用するスプライトデータ30バイトとソート
に必要なZ位置およびデータポインタをセットにして構成しています。Zバッファには、
ポリゴンデータへのアドレスが登録されており、NULLの場合はポリゴンデータが存在し
ません。
              Zバッファ　　　　　　　　　　ポリゴンデータ
            ------------           ----------          ----------
　　 Z = 0　|         -|-----------|->      |     /----|->      |
            ------------           |        |    /     |        |
　　 Z = 1　|   NULL   |           |        |   /      |        |
            ------------           |        |  /       |        |
　　 Z = 2　|   NULL   |           |  next -|-/        |  NULL  |
            ------------           ----------          ----------
    　　　　|          |
    　　　　|   ....   |           ポリゴンデータの構成
    　　　　|          |　　　　　　   -------------
            ------------            00 |  CMDCTRL  |
     Z =255 |   NULL   |            02 |  CMDLINK  |
            ------------            04 |  CMDPMOD  |
        ポインタがNULLの位置には    06 |  CMDCOLR  |
        ポリゴンが存在しない        08 |  CMDSRCA  |
                                    0A |  CMDSIZE  |
                                    0C |  CMDXA    |
                                    0E |  CMDYA    |
                                    10 |  CMDXB    |
                                    12 |  CMDYB    |
         ハード転送用テーブル       14 |  CMDXC    |
         --------------------       16 |  CMDYC    |
         |  転送サイズ      |       18 |  CMDXD    |
         --------------------       1A |  CMDYD    |
         |  転送先アドレス  |       1C |  CMDGRDA  |
         --------------------       1E |  CMDZPOS  |
         |  転送元アドレス  |       20 |  CMDNEXT  |
         --------------------          -------------
（５）ハードウェア(VDP1)への転送方法
　ハードウェア(VDP1)への転送には、SCU-DMAの間接モードを使用しています。
上記のZソートバッファを奥から順に読みだし、該当するデータアドレスを転送用のテー
ブルにセットします。

３−７　マスタCPUとスレーブCPU間のデータの受け渡しについて
　SEGASATURNに電源が投入されてアプリケーションプログラムが動作するまでは、スレ
ーブCPUは動作しておらず、マスタCPUのみで動作しています。マスタCPUとスレーブCPU
は同じバスを通して、メモリや他のデバイスに接続されているので、同じ動作をするこ
とができますが、うまく管理しないとマスタCPUとスレーブCPUのどちらか一方が待ち状
態になって、2CPUによる効率アップが望めない場合があります。
　SGLでは、slInitSystem関数を実行すると内部でスレーブCPUが動作し、SGL独自のスレ
ーブ管理関数が実行されて効率よく2CPUを使用できるようにしています。
　以下、SGLのスレーブCPUの管理方法について説明します。
　SGLでは、slInitSystem関数内のInitSlaveSh関数によってSMPCのリセットを解除して
FRTインプットキャプチャ待ち状態になります。ここで、SlaveCommandポインタ変数に
SlaveControl関数というSGLのスレーブCPU管理関数をセットして、FRTインプットキャプ
チャ信号を入力する(0x21000000番地に-1を書き込む)とスレーブCPUはSlaveControl関数
を実行します。
　SlaveControl関数はSGLのスレーブCPU管理関数で、マスタCPUとスレーブCPUのどちら
か一方が待ち状態になって効率ダウンしないように、マスタCPUからのリクエストを共有
のバッファ上で受け渡しするようにして、リクエストが出されたかどうかはマスタCPUか
らの書き込みポインタとスレーブCPUの読み込みポインタとが違った時とすることで認識
するようにしています。この方法によって、マスタCPUはリクエストをバッファに追加し
た時点で次の処理に移ることができるので、スレーブCPUの終了を待つ必要がないように
しています。
　SGL上でユーザがスレーブCPUを使用する場合、slSlaveFunc関数に実行する関数をセッ
トすると、SlaveControl関数の管理上で動作します。第一引数には、実行したいユーザ
関数を、第二引数にはこのユーザ関数の第一引数を渡します。
　また、スレーブCPUは割り込み関係がマスタCPUに比べてかなり制限があるので、SGLで
はマスタCPUで割り込み関係の処理を行うようにしています。


３−８　サウンドコントロールについて
　SGLのサウンドコントロールでは、大きく分けてシーケンス再生とPCMストリーム再生
の二つが使用できるようになっています。
　シーケンス再生とPCMストリーム再生は、それぞれ同時に8つまで使用することができ
ます。これらを使用する場合、発音管理番号というIDを用いてサウンドドライバの制御
を切り替えるわけですが、ユーザ側でそこまで考えるのは面倒です。そこで、SGLでは
BGMには0番を割り振り、効果音は1から7を使用することとして、効果音を出力する関数
を呼び出した際に空いている発音管理番号を見つけて出力させるようにすることで、ユ
ーザ側の負担を軽くしています。
　また、PCMストリーム再生ではマスタCPUからSCSPに対して、再生データを一定時間ご
とに転送しなければならないわけですが、PCMストリーム再生をワンショット再生(デー
タを始めから終わりまでただ出力するもので、ループなどの特殊処理を行わない)に限定
することで、ユーザが管理する必要をなくし、SGLの割り込み処理ルーチンの中でこの管
理を行うようになっています。
　また、ボリュームとパンが出力するデバイス(シーケンス、PCMストリーム、CDDA)によ
って有効範囲が異なっていたため、統一した数値で扱えるようにSGL内部で変換してサウ
ンドドライバに渡しています。
　　ボリューム：　   0〜 127(最大)
　　パン　　　：　-128、-127〜+127(-128ではパンの制御をしない)
　　　　　　　　　　　　Left: -127 << 0 >> +127 :Right
　サウンドコントロールファンクションは、サウンドドライバとハンドシェイクしなが
ら引き渡しされますが、ハンドシェイクの回数を減らすため、SGL内部にコマンド用のバ
ッファをセットし、バッファが一杯になるか、slSynch関数が実行された時にハンドシェ
イクするようになっています。(ただし、特定の関数においては即座にハンドシェイクさ
れます)
　ですから、サウンド出力関数を実行してもすぐにはサウンドドライバにデータ出力さ
れませんので注意してください。
　もし、サウンドドライバの機能を十分に使用したい場合は、SBLライブラリで提供して
いるサウンドI/Fライブラリを使用するようにしてください。(CinepakライブラリをSGL
で使用する場合は、必ずサウンドI/Fライブラリを使用する必要があります。)
　また、サウンドドライバはSEGA提供のサウンドドライバに対応しており、SGL/LIBディ
レクトリにあるSDDRVS.TSKを使用するようにお願いします。

４．ＳＧＬのトラブルシューティング

４−１  スプライト／ポリゴンの残像現象の対応について

　ＳＧＬで大量データやＣＤからのデータ読み込みによって、スプライト（ポリゴ
ンも含む）の残像が残った状態になる場合があります。
　ＳＧＬでは slSynch() 関数の実行により、スレーブＣＰＵにスプライト転送用の
リクエストテーブル作成ファンクションが送られ、Ｖブランク割り込み処理の中で
テーブルが作成済みであるかチェックし、作成されていればＳＣＵ−ＤＭＡを起動
してＶＤＰ１のＶＲＡＭに対してコマンドを転送します。
　ＶＤＰ１の表示コマンドはこの時にしか転送されませんので、ＶＤＰ１のＶＲＡＭ
には常に表示コマンドが残っていることになります。
　例えば、slSynch関数が実行されない場合や、割り込みを禁止した状態が一定時間
続くと、表示コマンド自体は残ったままになっていますので、当然スプライトは表示
されたままになります。
　残像が残っているという状態が発生した場合、上記の２点が実行されているかチェ
ックしてみてください。
　通常、ポリゴン(スプライト)を消すためには slSynch関数を余分に呼べばいいの
で、対策として以下のサンプルのようにしてください。
    void sample(){
        while(-1){
	    slDispSprite(...) ;
	    slPushMatrix() ;
	    {
	        slTranslate(...) ;
	        slRotY(...) ;
	        slPutPolygon(...) ;
	    }
	    slPopMatrix() ;
	    slSynch() ;		/* ここで、ＶＤＰ１に転送されます */
	    slSynch() ;		/* ここで、エンドコマンドだけが転送されます */
        }
    }

